/*******************************************************************************
 * Copyright (c) 2000, 2023 IBM Corporation and others.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.gef.ui.palette.editparts;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LayoutAnimator;

import org.eclipse.gef.internal.ui.palette.editparts.DrawerEditPart;
import org.eclipse.gef.internal.ui.palette.editparts.DrawerFigure;
import org.eclipse.gef.ui.palette.PaletteViewerPreferences;

/**
 * An animator for the layout of the palette.
 *
 * @author Randy Hudson, Pratik Shah
 */
public class PaletteAnimator extends LayoutAnimator {

	private final List<DrawerFigure> drawers = new ArrayList<>();
	private final PaletteViewerPreferences prefs;

	/**
	 * Constructor for a PaletteAnimator
	 *
	 * @param prefs The palette PaletteViewerPreferencesPreferences
	 */
	public PaletteAnimator(PaletteViewerPreferences prefs) {
		this.prefs = prefs;
	}

	/**
	 * Add a drawer to the palette.
	 *
	 * @param drawer the drawer.
	 */
	public void addDrawer(DrawerEditPart drawer) {
		drawers.add(drawer.getFigure());
	}

	/**
	 * Collapse the provided drawer if the automatoc collapse setting is enabled.
	 *
	 * @param openDrawer The drawer to collapse.
	 * @since 3.2
	 */
	protected void autoCollapse(DrawerFigure openDrawer) {
		int autoCollapseMode = prefs.getAutoCollapseSetting();

		// Collapse never
		if (autoCollapseMode == PaletteViewerPreferences.COLLAPSE_NEVER) {
			return;
		}

		// Collapse always
		if (autoCollapseMode == PaletteViewerPreferences.COLLAPSE_ALWAYS) {
			for (DrawerFigure drawer : drawers) {
				if (drawer != openDrawer) {
					drawer.setExpanded(false);
				}
			}
			return;
		}

		// Collapse as needed
		int wHint = openDrawer.getParent().getClientArea().width;
		int availableHeight = openDrawer.getParent().getSize().height;
		int requiredHeight = 0;
		List<DrawerFigure> closable = new ArrayList<>();
		for (IFigure sibling : openDrawer.getParent().getChildren()) {
			int height = sibling.getPreferredSize(wHint, -1).height;
			requiredHeight += height;
			if (!(sibling instanceof DrawerFigure drawer) || sibling == openDrawer) {
				continue;
			}
			if (drawer.isExpanded() && !drawer.isPinnedOpen()) {
				closable.add(drawer);
			}
		}

		// Start closing until requiredHeight <= available
		for (int i = closable.size() - 1; i >= 0 && requiredHeight > availableHeight; i--) {
			DrawerFigure drawer = closable.get(i);
			int expandedHeight = drawer.getPreferredSize(wHint, -1).height;
			drawer.setExpanded(false);
			int collapsedHeight = drawer.getPreferredSize(wHint, -1).height;
			requiredHeight -= (expandedHeight - collapsedHeight);
		}
	}

	/**
	 * @see org.eclipse.draw2d.Animator#playbackStarting(org.eclipse.draw2d.IFigure)
	 */
	@Override
	public void playbackStarting(IFigure figure) {
		if (figure instanceof DrawerFigure drawer) {
			drawer.setAnimating(true);
		}
	}

	/**
	 * Remove the drawer.
	 *
	 * @param drawer the drawer.
	 */
	public void removeDrawer(DrawerEditPart drawer) {
		drawers.remove(drawer.getFigure());
	}

	/**
	 * @see org.eclipse.draw2d.Animator#init(org.eclipse.draw2d.IFigure)
	 */
	@Override
	public void init(IFigure figure) {
		if (figure instanceof DrawerFigure drawer) {
			if (drawer.isExpanded()) {
				autoCollapse(drawer);
			}
			return;
		}
		super.init(figure);
	}

	/**
	 * @see org.eclipse.draw2d.Animator#tearDown(org.eclipse.draw2d.IFigure)
	 */
	@Override
	public void tearDown(IFigure figure) {
		if (figure instanceof DrawerFigure drawer) {
			drawer.setAnimating(false);
		}
	}

}
